#include <stdlib.h>
#include <i2c.h>
#include "rtc.h"
#include "smallsatos.h"
#include "int_eeprom.h"
#include "can_tx.h"

OS_EVENT* rtc_lock;
time_t system_time;

INT8U pcf8563_get(commande_rtc_t reg)
{
	INT8U data;

	StartI2C();
	WriteI2C(PCF8563_WADDR);
	WriteI2C(reg);
	RestartI2C();
	WriteI2C(PCF8563_RADDR);
	data = ReadI2C();
	StopI2C();

	return data;
}

void pcf8563_put(commande_rtc_t reg, INT8U data)
{
	StartI2C();
	WriteI2C(PCF8563_WADDR);
	WriteI2C(reg);
	WriteI2C(data);	
	StopI2C();
}


void init_rtc(void)
{
	pcf8563_put(RTC_ANNEES, 0x10);
	pcf8563_put(RTC_MOIS, 0x9);
	pcf8563_put(RTC_JOURS, 0x8);
	pcf8563_put(RTC_HEURES, 0x8);
	pcf8563_put(RTC_MINUTES, 0x36);
	pcf8563_put(RTC_SECONDES, 0x00);
}

char bcd_to_char (char bcd)
{
	return (bcd & 0xF) + (10 * (bcd >> 4));
}

void update_system_time(void)
{
    INT32U timestamp;
    INT32U n=0;

	/* Indice du tableau : mois */
	INT32U compteur_jours[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};

	INT32U annee, mois, jour, heure, minute, seconde;
	INT16U err;

	annee = 2000+bcd_to_char(pcf8563_get(RTC_ANNEES));
 	mois = bcd_to_char(pcf8563_get(RTC_MOIS) & 0x1F);
 	jour = bcd_to_char(pcf8563_get(RTC_JOURS) & 0x3F);
	heure = bcd_to_char(pcf8563_get(RTC_HEURES) & 0x3F);
	minute = bcd_to_char(pcf8563_get(RTC_MINUTES) & 0x7F);
	seconde = bcd_to_char(pcf8563_get(RTC_SECONDES) & 0x7F);
	

    /* Calculer le nombre de jours intercalaires entre 01/01/1970 et aujourd'hui */
    n = (annee - 1970) / 4;
    
    /* Si l'annee est bisextile mais le jour intercalaire (29 fevrier) ne s'est pas
     * deroule, il ne devrait pas etre compte.
     */
    if (!(annee % 4) && (mois < 2 || (mois == 2 && jour <= 29))) n--;
    
    timestamp = ((annee - 1970) * 365 + compteur_jours[mois-1] + jour - 1 + n) * 86400 +
                (heure * 3600) + (minute * 60) + seconde;
	
	set_system_time(timestamp);
}

void write_time(INT16U ad)
{
	INT16U err;
	time_t now;
	eeprom_query query;

	OSSemPend(rtc_lock, 0, &err);
	memcpy(&now, &system_time, sizeof(INT32U));
	OSSemPost(rtc_lock);
	

	query.type = WRITE_QUERY;
	query.address = ad;
	query.value = (INT8U*)&now;
	query.size = sizeof(time_t);

	OSSemPend(get_eeprom_lock(), 0, &err);
	OSMboxPost(get_eeprom_query_mbox(), &query);
	OSSemPost(get_eeprom_lock());
}

extern INT8U mode;

void rtc_task (void *pdata)
{
	INT8U syncCntr;
	INT8U led;
	INT16U err;
	INT8U data[8];
	
	INT32U uptime;

	can_param_t param;

	param.address = 0x001;
	param.length = 8;
	param.data = data;

	//init_rtc();
	
	//set_system_time(1279880255); /* TODO a remplacer par l'interrogation de la RTC */
	rtc_lock = OSSemCreate(1);
	
	syncCntr = 0;
	uptime = 0;

	for (;;)
	{	//LED0 = led; LED1 = led;
		OSTimeDlyHMSM(0,0,1,0);
		//led = ~led;
		OSSemPend(rtc_lock, 0, &err);
		system_time++;
		

		data[7] = mode;
		data[6] = (system_time >> 24) & 0xFF;
		data[5] = (system_time >> 16) & 0xFF;
		data[4] = (system_time >> 8) & 0xFF;
		data[3] = system_time & 0xFF;
		data[2] = uptime / 3600; /* Heures */
		data[1] = (uptime % 3600) / 60; /* Minutes */
		data[0] = (uptime % 3600) % 60; /* Secondes */

		syncCntr++;
		if (syncCntr == 60)
		{
			update_system_time();
			syncCntr = 0;
		}


		OSSemPost(rtc_lock);

		OSQPost(get_can_outgoing_queue(), &param);

		uptime++;


	}
}

OS_EVENT* get_rtc_lock (void)
{
	return rtc_lock;
}

void set_system_time (INT32U now)
{
	//INT16U err;
	//OSSemPend(rtc_lock, 0, &err);
	system_time = now;
	//OSSemPost(rtc_lock);
}